/////////////////////////////////////////////////////////////////
// Script:  starter script for cicp in second life
//          - starts cicp servlet
//          - processes cicp data from hub (which are mainly to
//            create a cicp prim that acts as a gateway selector)
//          - dies when cicp hub has finished sending initial data
//
/////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////
// constants
/////////////////////////////////////////////////////////////////

integer CICP_PRIM_CHANNEL       = -30973762; // channel to for all cicp prims (=atomic weight of Phosporus)
integer CICP_BACK_CHANNEL       = -30973770; // channel for responses to cicp init prim


/////////////////////////////////////////////////////////////////
// global vars
/////////////////////////////////////////////////////////////////

string  cicpUrl                 = ""; // url of the cicp hub
list    config                  = []; // contains configuration
list    httpParameters          = [ HTTP_METHOD, "GET",  // default HTTP parameters
                                    HTTP_MIMETYPE, "text/plain;charset=utf-8",
                                    HTTP_VERIFY_CERT, FALSE];
key     currentHttpRequestKey   = NULL_KEY; // key of last HTTP request
string  objectTitle             = "Glasshouse Starter"; // displayed title above script
vector  infoTextColor           = <0., 1., 0.>; // color of infoText
float   infoTextAlpha           = 1.; // alpha transparency of infoText

/////////////////////////////////////////////////////////////////
// functions
/////////////////////////////////////////////////////////////////

// reads a configuration variable and returns its value (see slcicp_init script)
string getConfig(string varName)
{
    integer varPos = llListFindList(llList2ListStrided(config, 0, -1, 2), (list)varName);
    if (~varPos) {
        varPos = (varPos << 1) + 1;
        return llList2String(config, varPos);
    }
    else {
        error("Config variable \"" + varName + "\" not found.");
        return "";
    }
}

// handles errors
error(string message)
{
    llOwnerSay(message);
}

// displays informative messages (see slcicp_init: info())
info(string message)
{
    llSetText(objectTitle + "\n" + message, infoTextColor, infoTextAlpha);
}

// processes line from cicp hub
processDispatchLine(string line)
{
    if (llGetSubString(line, 0, 4) == "error") {
        // an error occured
        error("CICP Hub Error: " + line);
    }
    else if (line == "more") {
        // line has not ended yet, request more data
        cicpRequest("type=dispatch&layer=0");
    }
    else if (line != "new" && line != "mod") {
        // data is supposed to be interpreted by a cicp prim
        list lineList = llParseString2List(line, [";"], []);
        // determine cicp prim's id
        integer targPrimId = llList2Integer(lineList, 0);
        integer targPrimChannel = -(targPrimId + (integer)getConfig("prim_channel_offset"));
        // redirect command to prim
        llRegionSay(targPrimChannel, "cicp," + llList2String(lineList, 1));
    }
}

cicpRequest(string queryString)
{
    currentHttpRequestKey = llHTTPRequest(cicpUrl + queryString, httpParameters, "");
}

/////////////////////////////////////////////////////////////////
//  states: default, waitingForTouch
/////////////////////////////////////////////////////////////////

 default {
     state_entry()
     {
         // listen on prim channel (mainly to receive config)
         llListen(CICP_PRIM_CHANNEL, "", NULL_KEY, "");

         // request config from slcicp
         llRegionSay(CICP_BACK_CHANNEL, "config");

         // display prim title
         info("Receiving config... Please wait.");
     }

     on_rez(integer i)
     {
         llResetScript();
     }

     listen(integer channel, string name, key id, string msg)
     {
         list parameters = llCSV2List(msg);
         // process commands
         if (llList2String(parameters, 0) == "config") {
             // hurray, it's the config! let's save it!
             config = llList2List(parameters, 1, -1);

             // save quick access variables
             cicpUrl = getConfig("cicp_url");
             httpParameters = llListReplaceList(httpParameters, [(integer)getConfig("ssl")], 5, 5);

             state waitingForTouch;
         }
     }
 }

state waitingForTouch
// wait for user to start cicp by touching this prim
{
    state_entry()
    {
        // show some information for the user
        info("Move prim and touch it to start CICP.");
    }

    touch_start(integer n)
    {
        // display information about what we're doing
        info("Requesting glasshouse gateway selector... Please wait.");

        // init cicp graph
        vector layerPos = llGetPos();
        string msg = "init," + (string)layerPos.x + "," +
        (string)layerPos.z + "," + (string)layerPos.y;

        cicpRequest("type=msg&msg=" + msg + "&region=" + llGetRegionName());
    }

    http_response (key requestId, integer status, list metadata, string body)
    {
        if (requestId == currentHttpRequestKey) {
            // process cicp init instructions
            // split into lines
            list bodyList = llParseString2List(body, ["\n"], []);
            integer lineCount = llGetListLength(bodyList) - 1;
            integer i;
            string line = "";
            // parse cicp instructions line per line
            // expected is to receive instructions for a cicp_prim that then
            // turns into a gateway selector that provides a menu with available
            // gateways to the user
            for (i = 0; i <= lineCount; i++) {
                line = llList2String(bodyList, i);

                processDispatchLine(line);
                if (i == lineCount && line != "more") {
                    // die since there seems to be no more data
                    // now it's the cicp prim's turn that has (hopefully)
                    // reacted on these commands
                    llDie();
                }
            }
        }
    }
}
